package com.dw.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description 将map转换为实体对象
 * @Author dw
 * @Date 2019/12/2 20:06
 * @Version 1.0
 **/
public class MapToEntityTool {

    //建立缓存的map集合
    private static  Map<String,EntityCacheItem> convertItemCache  = new HashMap<>();


    /**
     * 将map转换为实体对象
     *
     * @param map
     * @param entityClass
     * @return T
     */
    public static <T> T mapToEntity(Map<Object,Object> map,Class<T> entityClass){

        //尝试从缓存中获取对象
        EntityCacheItem entityCacheItem = convertItemCache.get(entityClass.getName());
        if(entityCacheItem == null){
            entityCacheItem = EntityCacheItem.createEntityCacheItem(entityClass);
            convertItemCache.put(entityClass.getName(),entityCacheItem);
        }

        List<String> fieldNameList  = entityCacheItem.getFieldNameList();
        Map<String,Method> setMethodMap = entityCacheItem.getSetMethodMap();
        T entity = null;
        try {
            //通过反射获取这个类型的一个对象
            entity = entityClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        Class<?>[] parameterTypes = null;
        Object mapFieldValue = null;
        Method sm = null;
        for (String fn: fieldNameList) {
            mapFieldValue = map.get(fn);
           if(mapFieldValue == null){
               continue;
           }
            sm = setMethodMap.get(fn);
           if(sm == null){
               continue;
           }
           //获取set方法中的参数类型的对象
             parameterTypes = sm.getParameterTypes();
           if(parameterTypes == null || parameterTypes.length > 1){
               continue;
           }
            //map中参数的属性值类型和set方法中参数类型一致，则调用set方法
           if(parameterTypes[0].isAssignableFrom(mapFieldValue.getClass())){
               //调用set方法注入属性值
               try {
                   sm.invoke(entity,mapFieldValue);
               } catch (Exception e) {
                   e.printStackTrace();
                   return null;
               }
           }
        }
        return entity;
    }

    static class EntityCacheItem{

       private EntityCacheItem(){}
       private List<String> fieldNameList = new ArrayList<>();
       private Map<String,Method> setMethodMap = new HashMap<>();

        public List<String> getFieldNameList() {
            return fieldNameList;
        }

        public Map<String, Method> getSetMethodMap() {
            return setMethodMap;
        }

        public void parseEntity(Class<?> entityClass){
            //1.通过类型参数获取类型里面的属性名称集合、set方法map集合
            Field[] fields = entityClass.getDeclaredFields();
            //2.遍历属性集合
            String fieldName;
            String setMethodName;
            Method setMethod = null;
            for (Field field : fields) {
                //3.打开获取私有属性的权限
                field.setAccessible(true);
                //4.得到属性名称
                fieldName = field.getName();
                fieldNameList.add(fieldName);
                setMethodName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                try {
                    setMethod = entityClass.getDeclaredMethod(setMethodName,field.getType());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                setMethodMap.put(fieldName,setMethod);
            }
        }
        public static EntityCacheItem createEntityCacheItem(Class<?> entityClass){
            EntityCacheItem entityCacheItem = new EntityCacheItem();
            entityCacheItem.parseEntity(entityClass);
            return entityCacheItem;
        }
    }
}
